package com.leyou.gateway.filter;

import com.leyou.common.auth.entity.Payload;
import com.leyou.common.auth.entity.UserInfo;
import com.leyou.common.auth.utils.JwtUtils;
import com.leyou.common.utils.CookieUtils;
import com.leyou.gateway.config.AuthFilterProperties;
import com.leyou.gateway.config.JwtProperties;
import com.netflix.zuul.ZuulFilter;
import com.netflix.zuul.context.RequestContext;
import com.netflix.zuul.exception.ZuulException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;

import java.util.List;

import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.FORM_BODY_WRAPPER_FILTER_ORDER;
import static org.springframework.cloud.netflix.zuul.filters.support.FilterConstants.PRE_TYPE;

/**
 * 用户登录过滤器
 */
@Slf4j
@Component
public class AuthFilter extends ZuulFilter {

    @Autowired
    private JwtProperties prop;
    @Autowired
    private AuthFilterProperties filterProperties;

    /**
     * 过滤器的类型
     * @return
     */
    @Override
    public String filterType() {
        return PRE_TYPE;
    }

    /**
     * 执行的顺序
     * 数字越小优先级越高
     * @return
     */
    @Override
    public int filterOrder() {
        return FORM_BODY_WRAPPER_FILTER_ORDER -1 ;
    }

    /**
     * 当前过滤器是否执行
     * @return true -执行  false -不执行
     */
    @Override
    public boolean shouldFilter() {
        return !isAllowPath();
    }

    /**
     * 验证请求路径是否在白名单中
     * 白名单存储在yml中
     * @return
     */
    private boolean isAllowPath() {
//        从配置对象中获取白名单列表
        List<String> allowPaths = filterProperties.getAllowPaths();
//                获取当前请求上下文
        RequestContext ctx = RequestContext.getCurrentContext();
//        获取当前请求的request对象
        HttpServletRequest request = ctx.getRequest();
//        获取当前请求路径
        String path = request.getRequestURI();
        log.info("path={}",path);
//        判断路径是否在白名单中 ,true- 白名单内容，需要背验证，false -不在白名单中，需要被验证
        for (String allowPath : allowPaths) {
            if(path.startsWith(allowPath)){
                return true;
            }
        }
        return false;
    }

    /**
     * 过滤器的业务逻辑
     * @return
     * @throws ZuulException
     */
    @Override
    public Object run() throws ZuulException {

//        获取当前请求上下文
        RequestContext ctx = RequestContext.getCurrentContext();
//         获取当前请求的request对象
        HttpServletRequest request = ctx.getRequest();
        try{
//        从cookie中，获取token
            String token = CookieUtils.getCookieValue(request, prop.getUserToken().getCookieName());
//        验证用户是否登录，验证token
            Payload<UserInfo> payloay = JwtUtils.getInfoFromToken(token, prop.getPublicKey(), UserInfo.class);
//            获取用户信息
            UserInfo userInfo = payloay.getUserInfo();
//            获取用户的角色
            String role = userInfo.getRole();
            String path = request.getRequestURI();
            //TODO 使用role和path 判断当前用户是否可以访问资源
            // TODO 判断权限，此处暂时空置，等待权限服务完成后补充
            log.info("【网关】用户{},角色{}。访问服务{} : {}，", userInfo.getUsername(), role, userInfo, path);
        }catch(Exception e){
//        如果用户没有登录，直接返回错误信息
//            网关判断登录有问题，没有任何的返回内容
            ctx.setSendZuulResponse(false);
//            设置状态码
            ctx.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());
            String remoteHost = request.getRemoteHost();
            log.error("非法访问，未登录，地址：{}", request.getRemoteHost(), e );
        }
        return null;
    }
}
